#!/usr/bin/env python
# coding=utf-8
import os
import sys
import json
import traceback
import time

from mns.account import Account,AccountMeta
from mns.queue import *
from mns.topic import *
from mns.subscription import *
from mns.mns_exception import *

from log import init, debug, info, warn, error
from utils import Singleton

# opinons
q_name = "QueueName"
t_name = "TopicName"
sub_name = "SubName"
# int
vistimeout = "VisibilityTimeout"
# int
maxmsgsize = "MaximumMessageSize"
# int
retentionperiod = "MessageRetentionPeriod"
# int
delaysec = "DelaySeconds"
# int
waitsec = "WaitSeconds"
# int
batchsize = "BatchSize"
# bool
loggingenabled = "LoggingEnabled"
# bool
base64enabled = "Base64Enabled"
messagebody = "MessageBody"
messages = "Messages"
messagetag = "MessageTag"
# int
priority = "Priority"
# queue name prefix
prefix = "Prefix"
# the max queue count of this request
retnum = "Retnum"
# the page start index of total records
marker = "Marker"
# the next page start index of total records
next_marker = "NextMarker"
queueurls = "QueueURLs"
subscriptioncurls = "SubURLs"
subscriptionurl = "SubURL"
# subscription meta
endpoint = "Endpoint"
filtertag = "FilterTag"
notifystrategy = "NotifyStrategy"
notifycontentformat = "NotifyContentFormat"
topicowner = "TopicOwner"
topicname = "TopicName"
subscriptionname = "SubscriptionName"

# response message member
status_code = "StatusCode"
message = "Message"
request_id = "RequestId"
q_url = "QueueUrl"
t_url = "TopicUrl"
s_message_id = "MessageID"
s_message_body_md5 = "MessageBodyMD5"
s_dequeue_count = "DequeueCount"
s_enqueue_time = "EnqueueTime"
s_first_dequeue_time = "FirstDequeueTime"
s_receip_handle = "ReceiptHandle"
s_receip_handle_list = "ReceiptHandleList"
s_next_visiable_time = "NextVisibleTime"
polling_wait_sec = "PollingWaitSeconds"
active_msg = "ActiveMessages"
inactive_msg = "InactiveMessages"
delay_msg = "DelayMessages"
create_time = "CreateTime"
last_modify_time = "LastModifyTime"
msg_rsp_attrs = "MessageResponseAttributes"
list_queue_num = "ListQueueNumber"
list_topic_num = "ListTopicNumber"
list_sub_num = "ListTopicNumber"

class WorkerQueue(Queue):

    cur_resp = None

    def create(self, queue_meta, req_info=None):
        """ 创建队列

            @type queue_meta: QueueMeta object
            @param queue_meta: QueueMeta对象，设置队列的属性

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @rtype: string
            @return 新创建队列的URL

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = CreateQueueRequest(self.queue_name, queue_meta.visibility_timeout, queue_meta.maximum_message_size,
                                 queue_meta.message_retention_period, queue_meta.delay_seconds,
                                 queue_meta.polling_wait_seconds, queue_meta.logging_enabled)
        req.set_req_info(req_info)
        resp = CreateQueueResponse()
        self.cur_resp = resp
        self.mns_client.create_queue(req, resp)
        self.debuginfo(resp)
        return resp.queue_url

    def get_attributes(self, req_info=None):
        """ 获取队列属性

            @rtype: QueueMeta object
            @return 队列的属性

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @note: Exception
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = GetQueueAttributesRequest(self.queue_name)
        req.set_req_info(req_info)
        resp = GetQueueAttributesResponse()
        self.cur_resp = resp
        self.mns_client.get_queue_attributes(req, resp)
        queue_meta = QueueMeta()
        self.__resp2meta__(queue_meta, resp)
        self.debuginfo(resp)
        return queue_meta

    def set_attributes(self, queue_meta, req_info=None):
        """ 设置队列属性

            @type queue_meta: QueueMeta object
            @param queue_meta: 新设置的属性

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = SetQueueAttributesRequest(self.queue_name, queue_meta.visibility_timeout, queue_meta.maximum_message_size,
                                        queue_meta.message_retention_period, queue_meta.delay_seconds,
                                        queue_meta.polling_wait_seconds, queue_meta.logging_enabled)
        req.set_req_info(req_info)
        resp = SetQueueAttributesResponse()
        self.cur_resp = resp
        self.mns_client.set_queue_attributes(req, resp)
        self.debuginfo(resp)

    def delete(self, req_info=None):
        """ 删除队列

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @note: Exception
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = DeleteQueueRequest(self.queue_name)
        req.set_req_info(req_info)
        resp = DeleteQueueResponse()
        self.cur_resp = resp
        self.mns_client.delete_queue(req, resp)
        self.debuginfo(resp)

    def send_message(self, message, req_info=None):
        """ 发送消息

            @type message: Message object
            @param message: 发送的Message object

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @rtype: Message object
            @return 消息发送成功的返回属性，包含MessageId和MessageBodyMD5

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = SendMessageRequest(self.queue_name, message.message_body, message.delay_seconds, message.priority,
                                 self.encoding)
        req.set_req_info(req_info)
        resp = SendMessageResponse()
        self.cur_resp = resp
        self.mns_client.send_message(req, resp)
        self.debuginfo(resp)
        return self.__send_resp2msg__(resp)

    def batch_send_message(self, messages, req_info=None):
        """批量发送消息

            @type messages: list of Message object
            @param messages: 发送的Message object list

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @rtype: list of Message object
            @return 多条消息发送成功的返回属性，包含MessageId和MessageBodyMD5

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = BatchSendMessageRequest(self.queue_name, self.encoding)
        req.set_req_info(req_info)
        for msg in messages:
            req.add_message(msg.message_body, msg.delay_seconds, msg.priority)
        resp = BatchSendMessageResponse()
        self.cur_resp = resp
        self.mns_client.batch_send_message(req, resp)
        self.debuginfo(resp)
        return self.__batchsend_resp2msg__(resp)

    def peek_message(self, req_info=None):
        """ 查看消息

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @rtype: Message object
            @return: Message object中包含消息的基本属性

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = PeekMessageRequest(self.queue_name)
        req.set_req_info(req_info)
        resp = PeekMessageResponse()
        self.cur_resp = resp
        self.mns_client.peek_message(req, resp)
        self.debuginfo(resp)
        return self.__peek_resp2msg__(resp)

    def batch_peek_message(self, batch_size, req_info=None):
        """ 批量查看消息

            @type batch_size: int
            @param batch_size: 本次请求最多获取的消息条数

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @rtype: list of Message object
            @return 多条消息的属性，包含消息的基本属性

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = BatchPeekMessageRequest(self.queue_name, batch_size)
        req.set_req_info(req_info)
        resp = BatchPeekMessageResponse()
        self.cur_resp = resp
        self.mns_client.batch_peek_message(req, resp)
        self.debuginfo(resp)
        return self.__batchpeek_resp2msg__(resp)

    def receive_message(self, wait_seconds=-1, req_info=None):
        """ 消费消息

            @type wait_seconds: int
            @param wait_seconds: 本次请求的长轮询时间，单位：秒

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @rtype: Message object
            @return Message object中包含基本属性、下次可消费时间和临时句柄

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = ReceiveMessageRequest(self.queue_name, self.encoding, wait_seconds)
        req.set_req_info(req_info)
        resp = ReceiveMessageResponse()
        self.cur_resp = resp
        self.mns_client.receive_message(req, resp)
        self.debuginfo(resp)
        return self.__recv_resp2msg__(resp)

    def batch_receive_message(self, batch_size, wait_seconds=-1, req_info=None):
        """ 批量消费消息

            @type batch_size: int
            @param batch_size: 本次请求最多获取的消息条数

            @type wait_seconds: int
            @param wait_seconds: 本次请求的长轮询时间，单位：秒

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @rtype: list of Message object
            @return 多条消息的属性，包含消息的基本属性、下次可消费时间和临时句柄

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = BatchReceiveMessageRequest(self.queue_name, batch_size, self.encoding, wait_seconds)
        req.set_req_info(req_info)
        resp = BatchReceiveMessageResponse()
        self.cur_resp = resp
        self.mns_client.batch_receive_message(req, resp)
        self.debuginfo(resp)
        return self.__batchrecv_resp2msg__(resp)

    def delete_message(self, receipt_handle, req_info=None):
        """ 删除消息

            @type receipt_handle: string
            @param receipt_handle: 最近一次操作该消息返回的临时句柄

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = DeleteMessageRequest(self.queue_name, receipt_handle)
        req.set_req_info(req_info)
        resp = DeleteMessageResponse()
        self.cur_resp = resp
        self.mns_client.delete_message(req, resp)
        self.debuginfo(resp)

    def batch_delete_message(self, receipt_handle_list, req_info=None):
        """批量删除消息

            @type receipt_handle_list: list
            @param receipt_handle_list: batch_receive_message返回的多条消息的临时句柄

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = BatchDeleteMessageRequest(self.queue_name, receipt_handle_list)
        req.set_req_info(req_info)
        resp = BatchDeleteMessageResponse()
        self.cur_resp = resp
        self.mns_client.batch_delete_message(req, resp)
        self.debuginfo(resp)

    def change_message_visibility(self, reciept_handle, visibility_timeout, req_info=None):
        """ 修改消息下次可消费时间

            @type reciept_handle: string
            @param reciept_handle: 最近一次操作该消息返回的临时句柄

            @type visibility_timeout: int
            @param visibility_timeout: 消息下次可被消费时间为
                                       now+visibility_timeout, 单位：秒

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @rtype: Message object
            @return: Message object包含临时句柄和下次可消费时间

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = ChangeMessageVisibilityRequest(self.queue_name, reciept_handle, visibility_timeout)
        req.set_req_info(req_info)
        resp = ChangeMessageVisibilityResponse()
        self.cur_resp = resp
        self.mns_client.change_message_visibility(req, resp)
        self.debuginfo(resp)
        return self.__changevis_resp2msg__(resp)

class WorkerTopic(Topic):

    cur_resp = None

    def create(self, topic_meta, req_info=None):
        """ 创建主题

            @type topic_meta: TopicMeta object
            @param topic_meta: TopicMeta对象，指定主题的属性

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @rtype: string
            @return 新创建队列的URL

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = CreateTopicRequest(self.topic_name, topic_meta.maximum_message_size, topic_meta.logging_enabled)
        req.set_req_info(req_info)
        resp = CreateTopicResponse()
        self.cur_resp = resp
        self.mns_client.create_topic(req, resp)
        self.debuginfo(resp)
        return resp.topic_url

    def get_attributes(self, req_info=None):
        """ 获取主题属性

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @rtype: TopicMeta object
            @return 主题的属性

            @note: Exception
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = GetTopicAttributesRequest(self.topic_name)
        req.set_req_info(req_info)
        resp = GetTopicAttributesResponse()
        self.cur_resp = resp
        self.mns_client.get_topic_attributes(req, resp)
        topic_meta = TopicMeta()
        self.__resp2meta__(topic_meta, resp)
        self.debuginfo(resp)
        return topic_meta

    def set_attributes(self, topic_meta, req_info=None):
        """ 设置队列属性

            @type topic_meta: TopicMeta object
            @param topic_meta: 新设置的主题属性

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = SetTopicAttributesRequest(self.topic_name, topic_meta.maximum_message_size, topic_meta.logging_enabled)
        req.set_req_info(req_info)
        resp = SetTopicAttributesResponse()
        self.cur_resp = resp
        self.mns_client.set_topic_attributes(req, resp)
        self.debuginfo(resp)

    def delete(self, req_info=None):
        """ 删除主题

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @note: Exception
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = DeleteTopicRequest(self.topic_name)
        req.set_req_info(req_info)
        resp = DeleteTopicResponse()
        self.cur_resp = resp
        self.mns_client.delete_topic(req, resp)
        self.debuginfo(resp)

    def publish_message(self, message, req_info=None):
        """ 发送消息

            @type message: TopicMessage object
            @param message: 发布的TopicMessage object

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @rtype: TopicMessage object
            @return: 消息发布成功的返回属性，包含MessageId和MessageBodyMD5

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = PublishMessageRequest(self.topic_name, message.message_body, message.message_tag, message.direct_mail, message.direct_sms)
        req.set_req_info(req_info)
        resp = PublishMessageResponse()
        self.cur_resp = resp
        self.mns_client.publish_message(req, resp)
        self.debuginfo(resp)
        return self.__publish_resp2msg__(resp)

    def list_subscription(self, prefix = "", ret_number = -1, marker = "", req_info=None):
        """ 列出该主题的订阅

            @type prefix: string
            @param prefix: 订阅名称的前缀

            @type ret_number: int
            @param ret_number: list_subscription最多返回的订阅个数

            @type marker: string
            @param marker: list_subscriptiond的起始位置，上次list_subscription返回的next_marker

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @rtype: tuple
            @return SubscriptionURL的列表,下次list subscription的起始位置;当所有订阅都返回时，next_marker为""

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = ListSubscriptionByTopicRequest(self.topic_name, prefix, ret_number, marker)
        req.set_req_info(req_info)
        resp = ListSubscriptionByTopicResponse()
        self.cur_resp = resp
        self.mns_client.list_subscription_by_topic(req, resp)
        self.debuginfo(resp)
        return resp.subscriptionurl_list, resp.next_marker

class WorkerSubscription(Subscription):

    cur_resp = None

    def subscribe(self, subscription_meta, req_info=None):
        """ 创建订阅

            @type subscription_meta: SubscriptionMeta object
            @param subscription_meta: SubscriptionMeta对象，指定订阅的属性

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @rtype: string
            @return 新创建订阅的URL

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = SubscribeRequest(self.topic_name,
                               self.subscription_name,
                               subscription_meta.endpoint,
                               subscription_meta.notify_strategy,
                               subscription_meta.notify_content_format,
                               subscription_meta.filter_tag)
        req.set_req_info(req_info)
        resp = SubscribeResponse()
        self.cur_resp = resp
        self.mns_client.subscribe(req, resp)
        self.debuginfo(resp)
        return resp.subscription_url

    def get_attributes(self, req_info=None):
        """ 获取订阅属性

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @rtype: SubscriptionMeta object
            @return 订阅的属性

            @note: Exception
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = GetSubscriptionAttributesRequest(self.topic_name, self.subscription_name)
        req.set_req_info(req_info)
        resp = GetSubscriptionAttributesResponse()
        self.cur_resp = resp
        self.mns_client.get_subscription_attributes(req, resp)
        subscription_meta = SubscriptionMeta()
        self.__resp2meta__(subscription_meta, resp)
        self.debuginfo(resp)
        return subscription_meta

    def set_attributes(self, subscription_meta, req_info=None):
        """ 设置订阅的属性

            @type subscription_meta: SubscriptionMeta object
            @param subscription_meta: 新设置的订阅属性

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = SetSubscriptionAttributesRequest(self.topic_name,
                                               self.subscription_name,
                                               subscription_meta.endpoint,
                                               subscription_meta.notify_strategy)
        req.set_req_info(req_info)
        resp = SetSubscriptionAttributesResponse()
        self.cur_resp = resp
        self.mns_client.set_subscription_attributes(req, resp)
        self.debuginfo(resp)

    def unsubscribe(self, req_info=None):
        """ 删除订阅

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @note: Exception
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = UnsubscribeRequest(self.topic_name, self.subscription_name)
        req.set_req_info(req_info)
        resp = UnsubscribeResponse()
        self.cur_resp = resp
        self.mns_client.unsubscribe(req, resp)
        self.debuginfo(resp)

class WorkerAccount(Account):

    cur_resp = None

    def get_queue(self, queue_name):
        """ 获取Account的一个Queue对象

            @type queue_name: string
            @param queue_name: 队列名

            @rtype: Queue object
            @return: 返回该Account的一个Queue对象
        """
        return WorkerQueue(queue_name, self.mns_client, self.debug)

    def get_topic(self, topic_name):
        """ 获取Account的一个Topic对象

            @type topic_name: string
            @param topic_name: 主题名称

            @rtype: Topic object
            @return: 返回该Account的一个Topic对象
        """
        return WorkerTopic(topic_name, self.mns_client, self.debug)

    def get_subscription(self, topic_name, subscription_name):
        """ 获取Account的一个Subscription对象

            @type topic_name: string
            @param topic_name: 主题名称

            @type subscription_name: string
            @param subscription_name: 订阅名称

            @rtype: Subscription object
            @return: 返回该Account指定Topic的一个Subscription对象
        """
        return WorkerSubscription(topic_name, subscription_name, self.mns_client, self.debug)

    def list_queue(self, prefix = "", ret_number = -1, marker = "", req_info=None):
        """ 列出Account的队列

            @type prefix: string
            @param prefix: 队列名的前缀

            @type ret_number: int
            @param ret_number: list_queue最多返回的队列数

            @type marker: string
            @param marker: list_queue的起始位置，上次list_queue返回的next_marker

            @rtype: tuple
            @return: QueueURL的列表和下次list queue的起始位置; 如果所有queue都list出来，next_marker为"".

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = ListQueueRequest(prefix, ret_number, marker)
        req.set_req_info(req_info)
        resp = ListQueueResponse()
        self.cur_resp = resp
        self.mns_client.list_queue(req, resp)
        self.debuginfo(resp)
        return resp.queueurl_list, resp.next_marker

    def list_topic(self, prefix = "", ret_number = -1, marker = "", req_info=None):
        """ 列出Account的主题

            @type prefix: string
            @param prefix: 主题名称的前缀

            @type ret_number: int
            @param ret_number: list_topic最多返回的主题个数

            @type marker: string
            @param marker: list_topic的起始位置，上次list_topic返回的next_marker

            @rtype: tuple
            @return: TopicURL的列表,下次list topic的起始位置, 如果所有主题都返回时，next_marker为""

            @type req_info: RequestInfo object
            @param req_info: 透传到MNS的请求信息

            @note: Exception
            :: MNSClientParameterException  参数格式异常
            :: MNSClientNetworkException    网络异常
            :: MNSServerException           mns处理异常
        """
        req = ListTopicRequest(prefix, ret_number, marker, True)
        req.set_req_info(req_info)
        resp = ListTopicResponse()
        self.cur_resp = resp
        self.mns_client.list_topic(req, resp)
        self.debuginfo(resp)
        return resp.topicurl_list, resp.next_marker

class ALiYunMnsOperation(Singleton):

    def __init__(self, ak, secret, account_id, region_id, debug=False):
        self.ak = ak
        self.secret = secret
        self.region_id = region_id
        self.account_id = account_id
        self.mnsendpoint = "https://%s.mns.%s.aliyuncs.com" % (self.account_id, self.region_id)
        self.token = ""
        self.account = WorkerAccount(self.mnsendpoint, self.ak, self.secret, self.token)
        self.account.set_debug(debug)

    @staticmethod
    def _init_queuemeta(**kwargs):
        queue_meta = QueueMeta()
        if vistimeout in kwargs:
            queue_meta.set_visibilitytimeout(kwargs[vistimeout])
        if maxmsgsize in kwargs:
            queue_meta.set_maximum_message_size(kwargs[maxmsgsize])
        if retentionperiod in kwargs:
            queue_meta.set_message_retention_period(kwargs[retentionperiod])
        if delaysec in kwargs:
            queue_meta.set_delay_seconds(kwargs[delaysec])
        if waitsec in kwargs:
            queue_meta.set_polling_wait_seconds(kwargs[waitsec])
        if loggingenabled in kwargs:
            queue_meta.set_logging_enabled(kwargs[loggingenabled])
        return queue_meta

    @staticmethod
    def _init_topicmeta(**kwargs):
        topic_meta = TopicMeta()
        if maxmsgsize in kwargs:
            topic_meta.set_maximum_message_size(kwargs[maxmsgsize])
        if loggingenabled in kwargs:
            topic_meta.set_logging_enabled(kwargs[loggingenabled])
        return topic_meta

    @staticmethod
    def _init_subscriptionmeta(**kwargs):
        subscription_meta = SubscriptionMeta()
        if endpoint in kwargs:
            subscription_meta.set_endpoint(kwargs[endpoint])
        if filtertag in kwargs:
            subscription_meta.set_filter_tag(kwargs[filtertag])
        if notifystrategy in kwargs:
            subscription_meta.set_notify_strategy(kwargs[notifystrategy])
        if notifycontentformat in kwargs:
            subscription_meta.set_notify_content_format(kwargs[notifycontentformat])
        return subscription_meta

    def CreateQueue(self, **kwargs):
        res = None
        queue = self.account.get_queue(kwargs[q_name])
        try:
            queue_meta = self._init_queuemeta(**kwargs)
            queue_url = queue.create(queue_meta)
            res = {
                status_code: "200",
                message: "",
                request_id: queue.cur_resp.header["x-mns-request-id"],
                q_url: queue_url
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to create queue due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: queue.cur_resp.header["x-mns-request-id"],
                q_url: ""
            }
        return res

    def GetQueueAttribute(self, **kwargs):
        res = None
        queue = self.account.get_queue(kwargs[q_name])
        try:
            queue_meta = queue.get_attributes()
            res = {
                status_code: "200",
                message: "",
                request_id: queue.cur_resp.header["x-mns-request-id"],
                vistimeout: queue_meta.visibility_timeout,
                maxmsgsize: queue_meta.maximum_message_size,
                retentionperiod: queue_meta.message_retention_period,
                delaysec: queue_meta.delay_seconds,
                polling_wait_sec: queue_meta.polling_wait_seconds,
                active_msg: queue_meta.active_messages,
                inactive_msg: queue_meta.inactive_messages,
                delay_msg: queue_meta.delay_messages,
                create_time: time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(queue_meta.create_time)),
                last_modify_time: time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(queue_meta.last_modify_time)),
                q_name: queue_meta.queue_name,
                loggingenabled: queue_meta.logging_enabled
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to get queue attribute due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: queue.cur_resp.header["x-mns-request-id"]
            }
        return res

    def SetQueueAttribute(self, **kwargs):
        res = None
        queue = self.account.get_queue(kwargs[q_name])
        try:
            queue_meta = self._init_queuemeta(**kwargs)
            queue.set_attributes(queue_meta)
            res = {
                status_code: "200",
                message: "",
                request_id: queue.cur_resp.header["x-mns-request-id"]
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to set queue attribute due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: queue.cur_resp.header["x-mns-request-id"]
            }
        return res

    def ListQueue(self, **kwargs):
        res = None
        try:
            _prefix = "" if prefix not in kwargs else kwargs[prefix]
            _retnum = -1 if retnum not in kwargs else kwargs[retnum]
            _marker = "" if marker not in kwargs else kwargs[marker]
            queueurl_list, nextmarker = self.account.list_queue(_prefix, _retnum, _marker)
            ret_msg = "Successful get the list of queue."
            if len(queueurl_list) == 0:
                ret_msg = "Queue not exist in this account."

            res = {
                status_code: "200",
                message: ret_msg,
                request_id: self.account.cur_resp.header["x-mns-request-id"],
                next_marker: nextmarker,
                list_queue_num: len(queueurl_list),
                queueurls: queueurl_list
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to set queue attribute due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: self.account.cur_resp.header["x-mns-request-id"]
            }
        return res

    def DeleteQueue(self, **kwargs):
        res = None
        queue = self.account.get_queue(kwargs[q_name])
        try:
            queue.delete()
            res = {
                status_code: "200",
                message: "",
                request_id: queue.cur_resp.header["x-mns-request-id"]
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to delete queue due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: queue.cur_resp.header["x-mns-request-id"]
            }
        return res

    def SendMessage(self, **kwargs):
        res = None
        queue = self.account.get_queue(kwargs[q_name])
        try:
            if base64enabled in kwargs:
                queue.set_encoding(kwargs[base64enabled])

            msg = Message(kwargs[messagebody])

            if delaysec in kwargs:
                msg.set_delayseconds(kwargs[delaysec])

            if priority in kwargs:
                msg.set_priority(kwargs[priority])

            rmsg = queue.send_message(msg)
            res = {
                status_code: "200",
                message: kwargs[messagebody],
                request_id: queue.cur_resp.header["x-mns-request-id"],
                s_message_id: rmsg.message_id,
                s_message_body_md5: rmsg.message_body_md5
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to send message due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: queue.cur_resp.header["x-mns-request-id"]
            }
        return res

    def BatchSendMessage(self, **kwargs):
        """

        :param kwargs["Messages"]: [{"MessageBody":"", "DelaySeconds":"", "Priority":""}, ...]
        :return:
        """
        res = None
        queue = self.account.get_queue(kwargs[q_name])
        try:
            if base64enabled in kwargs:
                queue.set_encoding(kwargs[base64enabled])
            msg_info_list = kwargs[messages]
            msgs = []
            for msg_info in msg_info_list:

                msg = Message(msg_info[messagebody])

                if delaysec in msg_info:
                    msg.set_delayseconds(msg_info[delaysec])

                if priority in kwargs:
                    msg.set_priority(msg_info[priority])

                msgs.append(msg)

            rmsgs = queue.batch_send_message(msgs)
            res = {
                status_code: "200",
                message: "",
                request_id: queue.cur_resp.header["x-mns-request-id"],
                msg_rsp_attrs: list(map(lambda rmsg:{
                    s_message_id: rmsg.message_id,
                    s_message_body_md5: rmsg.message_body_md5
                }, rmsgs))
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to batch send message due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: queue.cur_resp.header["x-mns-request-id"]
            }
        return res

    def ReceiveMessage(self, **kwargs):
        # 消费的消息必须要手动调用删除消息的api在next visible time之前
        # 删除掉

        res = None
        queue = self.account.get_queue(kwargs[q_name])
        try:
            queue = self.account.get_queue(kwargs[q_name])
            if base64enabled in kwargs:
                queue.set_encoding(kwargs[base64enabled])
            wait_second = -1 if waitsec not in kwargs else kwargs[waitsec]
            rmsg = queue.receive_message(wait_second)

            res = {
                status_code: "200",
                message: rmsg.message_body,
                request_id: queue.cur_resp.header["x-mns-request-id"],
                s_message_id: rmsg.message_id,
                s_message_body_md5: rmsg.message_body_md5,
                s_dequeue_count: rmsg.dequeue_count,
                s_enqueue_time: rmsg.enqueue_time,
                s_first_dequeue_time: rmsg.first_dequeue_time,
                priority: rmsg.priority,
                s_receip_handle: rmsg.receipt_handle,
                s_next_visiable_time: rmsg.next_visible_time
            }

        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to receive message due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: queue.cur_resp.header["x-mns-request-id"]
            }
        return res

    def BatchReceiveMessage(self, **kwargs):
        res = None
        queue = self.account.get_queue(kwargs[q_name])
        try:
            queue = self.account.get_queue(kwargs[q_name])
            if base64enabled in kwargs:
                queue.set_encoding(kwargs[base64enabled])
            wait_second = -1 if waitsec not in kwargs else kwargs[waitsec]
            batch_size = 1 if batchsize not in kwargs else kwargs[batchsize]
            rmsgs = queue.batch_receive_message(batch_size, wait_second)

            res = {
                status_code: "200",
                message: "",
                request_id: queue.cur_resp.header["x-mns-request-id"],
                msg_rsp_attrs: list(map(lambda rmsg:{
                    messagebody: rmsg.message_body,
                    s_message_id: rmsg.message_id,
                    s_message_body_md5: rmsg.message_body_md5,
                    s_dequeue_count: rmsg.dequeue_count,
                    s_enqueue_time: rmsg.enqueue_time,
                    s_first_dequeue_time: rmsg.first_dequeue_time,
                    priority: rmsg.priority,
                    s_receip_handle: rmsg.receipt_handle,
                    s_next_visiable_time: rmsg.next_visible_time
                }, rmsgs))
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to batch receive messages due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: queue.cur_resp.header["x-mns-request-id"]
            }
        return res

    def PeekMessage(self, **kwargs):
        res = None
        queue = self.account.get_queue(kwargs[q_name])
        try:
            rmsg = queue.peek_message()
            res = {
                status_code: "200",
                message: rmsg.message_body,
                request_id: queue.cur_resp.header["x-mns-request-id"],
                s_message_id: rmsg.message_id,
                s_message_body_md5: rmsg.message_body_md5,
                s_dequeue_count: rmsg.dequeue_count,
                s_enqueue_time: rmsg.enqueue_time,
                s_first_dequeue_time: rmsg.first_dequeue_time,
                priority: rmsg.priority
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to peek message due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: queue.cur_resp.header["x-mns-request-id"]
            }
        return res

    def BatchPeekMessage(self, **kwargs):
        res = None
        queue = self.account.get_queue(kwargs[q_name])
        try:
            batch_size = 1 if batchsize not in kwargs else kwargs[batchsize]
            rmsgs = queue.batch_peek_message(batch_size)
            res = {
                status_code: "200",
                message: "",
                request_id: queue.cur_resp.header["x-mns-request-id"],
                msg_rsp_attrs: list(map(lambda rmsg:{
                    messagebody: rmsg.message_body,
                    s_message_id: rmsg.message_id,
                    s_message_body_md5: rmsg.message_body_md5,
                    s_dequeue_count: rmsg.dequeue_count,
                    s_enqueue_time: rmsg.enqueue_time,
                    s_first_dequeue_time: rmsg.first_dequeue_time,
                    priority: rmsg.priority
                }, rmsgs))
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to batch peek messages due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: queue.cur_resp.header["x-mns-request-id"]
            }
        return res

    def DeleteMessage(self, **kwargs):
        # 消费消息产生的临时句柄，用于删除和修改处于
        # Inactive 消息，NextVisibleTime 之前有效。

        res = None
        queue = self.account.get_queue(kwargs[q_name])
        try:
            queue.delete_message(kwargs[s_receip_handle])
            res = {
                status_code: "200",
                message: "",
                request_id: queue.cur_resp.header["x-mns-request-id"]
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to delete message due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: queue.cur_resp.header["x-mns-request-id"]
            }
        return res

    def BatchDeleteMessage(self, **kwargs):
        res = None
        queue = self.account.get_queue(kwargs[q_name])
        try:
            queue.batch_delete_message(kwargs[s_receip_handle_list])
            res = {
                status_code: "200",
                message: "",
                request_id: queue.cur_resp.header["x-mns-request-id"]
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to batch delete message due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: queue.cur_resp.header["x-mns-request-id"]
            }
        return res

    def ChangeVisibility(self, **kwargs):
        res = None
        queue = self.account.get_queue(kwargs[q_name])
        try:
            rmsg = queue.change_message_visibility(kwargs[s_receip_handle], kwargs[vistimeout])

            res = {
                status_code: "200",
                message: rmsg.message_body,
                s_receip_handle: rmsg.receipt_handle,
                s_next_visiable_time: rmsg.next_visible_time,
                request_id: queue.cur_resp.header["x-mns-request-id"]
            }

        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to change visibility due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: queue.cur_resp.header["x-mns-request-id"]
            }
        return res

    def ListTopic(self, **kwargs):
        res = None
        try:
            _prefix = "" if prefix not in kwargs else kwargs[prefix]
            _retnum = -1 if retnum not in kwargs else kwargs[retnum]
            _marker = "" if marker not in kwargs else kwargs[marker]
            topic_list, nextmarker = self.account.list_topic(_prefix, _retnum, _marker)
            ret_msg = "Successful get the list of queue."
            if len(topic_list) == 0:
                ret_msg = "Queue not exist in this account."
            res = {
                status_code: "200",
                message: ret_msg,
                request_id: self.account.cur_resp.header["x-mns-request-id"],
                next_marker: nextmarker,
                list_topic_num: len(topic_list),
                queueurls: topic_list
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to get topic due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: self.account.cur_resp.header["x-mns-request-id"]
            }
        return res

    def CreateTopic(self, **kwargs):
        res = None
        topic = self.account.get_topic(kwargs[t_name])
        try:
            topic_meta = self._init_topicmeta(**kwargs)
            topic_url = topic.create(topic_meta)
            res = {
                status_code: "200",
                message: "",
                request_id: topic.cur_resp.header["x-mns-request-id"],
                t_url: topic_url
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to create topic due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: topic.cur_resp.header["x-mns-request-id"]
            }
        return res

    def SetTopicAttribute(self, **kwargs):
        res = None
        topic = self.account.get_topic(kwargs[t_name])
        try:
            topic_meta = self._init_topicmeta(**kwargs)
            topic.set_attributes(topic_meta)
            res = {
                status_code: "200",
                message: "",
                request_id: topic.cur_resp.header["x-mns-request-id"]
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to set topic attribute due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: topic.cur_resp.header["x-mns-request-id"]
            }
        return res

    def GetTopicAttribute(self, **kwargs):
        res = None
        topic = self.account.get_topic(kwargs[t_name])
        try:
            topic_meta = topic.get_attributes()
            res = {
                status_code: "200",
                message: "",
                request_id: topic.cur_resp.header["x-mns-request-id"],
                maxmsgsize: topic_meta.maximum_message_size,
                loggingenabled: topic_meta.logging_enabled
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to get topic attribute due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: topic.cur_resp.header["x-mns-request-id"]
            }
        return res

    def DeleteTopic(self, **kwargs):
        res = None
        topic = self.account.get_topic(kwargs[t_name])
        try:
            topic.delete()
            res = {
                status_code: "200",
                message: "",
                request_id: topic.cur_resp.header["x-mns-request-id"]
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to delete topic attribute due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: topic.cur_resp.header["x-mns-request-id"]
            }
        return res

    def PublishMessage(self, **kwargs):
        res = None
        topic = self.account.get_topic(kwargs[t_name])
        try:
            msg = TopicMessage(kwargs[messagebody])
            if messagetag in kwargs:
                msg.set_message_tag(kwargs[messagetag])
            rmsg = topic.publish_message(msg)
            res = {
                status_code: "200",
                message: kwargs[messagebody],
                request_id: topic.cur_resp.header["x-mns-request-id"],
                s_message_id: rmsg.message_id,
                s_message_body_md5: rmsg.message_body_md5
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to publish message due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: topic.cur_resp.header["x-mns-request-id"]
            }
        return res

    def ListSub(self, **kwargs):
        res = None
        topic = self.account.get_topic(kwargs[t_name])
        try:
            _prefix = "" if prefix not in kwargs else kwargs[prefix]
            _retnum = -1 if retnum not in kwargs else kwargs[retnum]
            _marker = "" if marker not in kwargs else kwargs[marker]

            suburl_list, nextmarker = topic.list_subscription(_prefix, _retnum, _marker)
            ret_msg = "Successful get the list of topic."
            if len(suburl_list) == 0:
                ret_msg = "Subscription not exist in this account."

            res = {
                status_code: "200",
                message: ret_msg,
                request_id: topic.cur_resp.header["x-mns-request-id"],
                next_marker: nextmarker,
                list_sub_num: len(suburl_list),
                subscriptioncurls: suburl_list
            }

        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to list subscription due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: topic.cur_resp.header["x-mns-request-id"]
            }
        return res

    def Subscribe(self, **kwargs):
        res = None
        subscription = self.account.get_subscription(kwargs[t_name], kwargs[sub_name])
        try:
            subscription_meta = self._init_subscriptionmeta(**kwargs)
            subscription_url = subscription.subscribe(subscription_meta)
            res = {
                status_code: "200",
                message: "",
                request_id: subscription.cur_resp.header["x-mns-request-id"],
                subscriptionurl: subscription_url
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to subscribe due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: subscription.cur_resp.header["x-mns-request-id"]
            }
        return res

    def SetSubAttribute(self, **kwargs):
        res = None
        subscription = self.account.get_subscription(kwargs[t_name], kwargs[sub_name])
        try:
            subscription_meta = self._init_subscriptionmeta(**kwargs)
            subscription.set_attributes(subscription_meta)
            res = {
                status_code: "200",
                message: "",
                request_id: subscription.cur_resp.header["x-mns-request-id"]
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to set subscription attribute due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: subscription.cur_resp.header["x-mns-request-id"]
            }
        return res

    def GetSubAttribute(self, **kwargs):
        res = None
        subscription = self.account.get_subscription(kwargs[t_name], kwargs[sub_name])
        try:
            sub_meta = subscription.get_attributes()
            res = {
                status_code: "200",
                message: "",
                request_id: subscription.cur_resp.header["x-mns-request-id"],
                topicowner: sub_meta.topic_owner,
                topicname: sub_meta.topic_name,
                subscriptionname : sub_meta.subscription_name,
                endpoint: sub_meta.endpoint,
                filtertag: sub_meta.filter_tag,
                notifystrategy: sub_meta.notify_strategy,
                notifycontentformat: sub_meta.notify_content_format,
                create_time: time.strftime("%Y/%m/%d %H:%M:%S",
                                           time.localtime(subscription.cur_resp.create_time)),
                last_modify_time: time.strftime("%Y/%m/%d %H:%M:%S",
                                                time.localtime(subscription.cur_resp.last_modify_time))
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to get subscription attribute due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: subscription.cur_resp.header["x-mns-request-id"]
            }
        return res

    def UnSubscribe(self, **kwargs):
        res = None
        subscription = self.account.get_subscription(kwargs[t_name], kwargs[sub_name])
        try:
            subscription.unsubscribe()
            res = {
                status_code: "200",
                message: "",
                request_id: subscription.cur_resp.header["x-mns-request-id"]
            }
        except MNSExceptionBase as ex:
            error(traceback.format_exc())
            error("Failed to unsubscribe due to %s." % (ex))
            res = {
                status_code: "403",
                message: str(ex),
                request_id: subscription.cur_resp.header["x-mns-request-id"]
            }
        return res
